package com.showcai.service.impl;

import com.showcai.module.*;
import com.showcai.module.wechat.WXJSConfig;
import com.showcai.module.wechat.WXJsApiParam;
import com.showcai.module.wechat.WeChatNotification;
import com.showcai.myRunTime.MyRunTimeExcption;
import com.showcai.service.OrderService;
import com.showcai.service.PayService;
import com.showcai.service.WeChatOrderFeedbackService;
import com.showcai.service.WeChatPaymentFeedbackService;
import com.showcai.util.*;
import com.showcai.utils.WeiXinUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * Created by Baggio on 2017-3-19.
 */
@Service("weChatPayService")
public class WeChatPayServiceImpl extends PayBase implements PayService {
    @Autowired
    private WeChatPaymentFeedbackService weChatPaymentFeedbackService;

    @Autowired
    private WeChatOrderFeedbackService weChatOrderFeedbackService;

    @Autowired
    private OrderService orderService;



    @Override
    public String getPayParameterStr(Long orderId, Integer price, String remoteAddr, Map<String, String> payParametersMap) {

        List<WeChatPaymentFeedback> paymentFeedbacksList = weChatPaymentFeedbackService
                .findWeChatPaymentFeedbackByOutTradeNo(String.valueOf(orderId));

        if (!paymentFeedbacksList.isEmpty()) {
            throw new MyRunTimeExcption("【订单已经生成过了。。。。。。。】");
        }

        Map<String, String> parameterMap = new HashMap<String, String>();
        parameterMap.put("appid", FixedData.ENTERPRISE_APP_ID);
        parameterMap.put("mch_id", FixedData.MERCHANT_NUMBER);
        parameterMap.put("nonce_str", GenerateID.getRandomNum(32, false));
        parameterMap.put("body", this.getProductName(String.valueOf(orderId)));
        parameterMap.put("out_trade_no", String.valueOf(orderId));
        parameterMap.put("total_fee", String.valueOf(price));
        parameterMap.put("spbill_create_ip", remoteAddr);
        parameterMap.put("notify_url", FixedData.ASYNCHRONOUS_RECEPTION);         // 微信异步反馈下订单结果信息的地址
        parameterMap.put("trade_type", "JSAPI");
        parameterMap.put("openid", payParametersMap.get("openid"));   //


        // 字段组合并字典排序最后MD5加密
        String sign_tmp = WeChatNotification.dictionarySorting(parameterMap) + "&key=" + FixedData.WX_KEY;
        String sign = MD5Tools.MD5(sign_tmp).toUpperCase();
        parameterMap.put("sign", sign);
        logger.warn("【组装后的字典排序sign_tmp：" + sign_tmp + "】。。。。。。");
        logger.warn("【最后生成的加密字段sign：" + sign + "】。。。。。。");
        String requestString = XmlAnalysisTools.stringToWxForXML(parameterMap);
        return requestString;
    }

    @Override
    public PayParameter pay( Long orderId, Integer price,String dataString,String ticket) throws Exception {
        String payUrl="http://www.showcai.com/pay/"+orderId+".html";
        PayParameter payParameter = new PayParameter();
        Order order = orderService.getOrderById(orderId);
        try {


            Map<String, String> resultMap = XmlAnalysisTools.getResultMap(dataString);

            logger.warn("【下单结果回调参数内容体：" + dataString + "】。。。。。。");

            if (null == resultMap) {
                logger.warn("【XML解析错误。。。。。。】");
                throw new MyRunTimeExcption("【XML解析错误。。。。。。】");
            }

            String returnCode = resultMap.get("return_code");
            String resultCode = resultMap.get("result_code");
            String errCode = resultMap.get("err_code");
            String wxSign = resultMap.get("sign");
            String prepay_id = resultMap.get("prepay_id");

            if ("FAIL".equals(returnCode)) {
                logger.warn("【下单请求失败。。。。。。】");
            //  String errorMessage = WeChatNotification.getMessage(errCode);

                throw new MyRunTimeExcption("下单请求失败");
            }

            if ("SUCCESS".equals(returnCode) && "SUCCESS".equals(resultCode)) {

                String localWxSignTemp = WeChatNotification.dictionarySortingWxFeedBack(resultMap);
                logger.info("localWxSignTemp===>"+localWxSignTemp);
                String localWxSign = MD5Tools.MD5(localWxSignTemp + "&key=" + FixedData.WX_KEY).toUpperCase();

                if (null == wxSign || !wxSign.equals(localWxSign)) {
                    logger.warn("【本地得出反馈签名：" + localWxSign + "】。。。。。。");
                    logger.warn("【微信得出反馈签名：" + wxSign + "】。。。。。。");
                    logger.warn("【微信反馈签名和本地签名不一致。。。。。。】");
                    throw new MyRunTimeExcption("【微信反馈签名和本地签名不一致。。。。。。】");
                } else {
                    logger.warn("【订单请求成功。。。。。。】");
                    logger.warn("【本地得出反馈签名：" + localWxSign + "】。。。。。。");
                    logger.warn("【微信得出反馈签名：" + wxSign + "】。。。。。。");
                    logger.warn("【二维码地址为：" + resultMap.get("code_url") + "】。。。。。。");

                    // 创建微信订单信息
                    WeChatOrderFeedback weChatOrderFeedback = WeChatNotification
                            .InjectedObj(new WeChatOrderFeedback(), resultMap, true);
                    weChatOrderFeedback.setOrderFeedbackId(GenerateID.CreatetID());
                    weChatOrderFeedback.setOrderId(String.valueOf(orderId));
                    weChatOrderFeedback.setCreateTime(new Date());
                    weChatOrderFeedbackService.createWeChatOrderFeedback(weChatOrderFeedback);

                    // 为返回二维码页面准备相应信息
                    String codeUrl = resultMap.get("code_url");
                    Map<String, String> returnMap = new HashMap<String, String>();
                    returnMap.put("orderFeedbackId", new String(weChatOrderFeedback.getOrderFeedbackId().toString()));
                    returnMap.put("price", String.valueOf(price));
                    returnMap.put("codeUrl", codeUrl);
                    returnMap.put("orderId", String.valueOf(orderId));
                    returnMap.put("prepay_id", prepay_id);

                    returnMap.put("customerId", String.valueOf(order.getUserId().longValue()));

                    WXJsApiParam wxJsApiParam=getPayConfig(FixedData.ENTERPRISE_APP_ID,prepay_id);
                    logger.warn("【wxJsApiParam。。。。。。。。。。。。。。。。。。】");
                    returnMap.put("appId",wxJsApiParam.getAppId());
                    returnMap.put("wxJsApiParamNonceStr",wxJsApiParam.getNonceStr());
                    returnMap.put("PackAge",wxJsApiParam.getPackAge());
                    returnMap.put("PaySign",wxJsApiParam.getPaySign());
                    returnMap.put("wxJsApiParamTimeStamp",wxJsApiParam.getTimeStamp());
                    returnMap.put("wxJsApiParamSignType",wxJsApiParam.getSignType());

                    WXJSConfig wxConfig=getWXConfig(FixedData.ENTERPRISE_APP_ID,payUrl,ticket);
                    logger.warn("【getWXConfig。。。。。。。。。。。。。。。。。。】");
                    returnMap.put("wxConfigNonceStr",wxConfig.getNonceStr());
                    returnMap.put("wxConfigJsApiList",wxConfig.getJsApiList());
                    returnMap.put("Signature",wxConfig.getSignature());
                    returnMap.put("wxConfigTimeStamp",wxConfig.getTimestamp());
                    payParameter.setMap(returnMap);
                    payParameter.setBankUrl("/wechat_pay/topayjs");
                    logger.warn("【返回。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。】");
                    return payParameter;
                }
            } else {
                logger.warn("【系统请求失败。。。。。。】");
                throw new MyRunTimeExcption("【系统请求失败。。。。。。】");
            }
        } catch (MyRunTimeExcption e) {
            logger.warn("【" + e.getMessage() + "。。。。。。】");
            throw new MyRunTimeExcption(e.getMessage());
        }

    }

   private WXJsApiParam getPayConfig(String appId, String prepay_id) throws Exception {
        // WeiXinUtils.getSort(map);
        Map<String, String> map = new TreeMap<String, String>();
        String timeStamp = DateUtil.DateToTimestamp(new Date()).toString();
        map.put("appId", appId);
        map.put("timeStamp", timeStamp);
        map.put("package", "prepay_id=" + prepay_id);
        map.put("signType", "MD5");
        String nonceStr = GenerateID.getUUID().toUpperCase();
        map.put("nonceStr", nonceStr);
        String paySign = WeiXinUtils.MakeSign(map, FixedData.WX_KEY);
       logger.info("getWXOrderConfig+++=====================" + paySign);
        WXJsApiParam wxJsApiParam = new WXJsApiParam();
        wxJsApiParam.setTimeStamp(timeStamp);
        wxJsApiParam.setNonceStr(nonceStr);
        wxJsApiParam.setPackAge("prepay_id=" + prepay_id);
        wxJsApiParam.setPaySign(paySign);
        wxJsApiParam.setAppId(appId);
        wxJsApiParam.setSignType(paySign);
        return wxJsApiParam;
    }

    private WXJSConfig getWXConfig(String appID, String url,String ticket) throws Exception {

        if (StringUtils.isBlank(appID)) {
            throw new Exception("appID is null");
        }
        Map<String, String> map = new TreeMap<String, String>();
        String timeStamp = DateUtil.DateToTimestamp(new Date()).toString();
        map.put("timestamp", timeStamp);
        WXJSConfig wxJSConfig = new WXJSConfig();
        wxJSConfig.setAppId(appID);
        wxJSConfig.setTimestamp(timeStamp);
        wxJSConfig.setDebug(true);
        String nonceStr = GenerateID.getUUID().toUpperCase();
        map.put("noncestr", nonceStr);
        wxJSConfig.setNonceStr(nonceStr);


        map.put("url", url);
        map.put("jsapi_ticket", ticket);
        String Str1 = WeiXinUtils.getSort(map);
       logger.info("getWXConfigStr1   ====================" + Str1);
        String signature = SHA1.genStr(Str1);
        logger.info("getWXConfig signature====================" + signature);
        wxJSConfig.setSignature(signature);
        wxJSConfig.setJsApiList(Str1 + "<p>" + signature);
        return wxJSConfig;
    }




    @Override
    public Map<String, String> notification(Map<String, String> map) {
        logger.info("【微信支付回调。。。。。。】");
        // 从XML获取成MAP对象
        String xml = map.get("xml");
        logger.info(xml);
        Map<String, String> resultMap = XmlAnalysisTools.getResultMap(xml);
        if(null == resultMap) {
            logger.warn("【XML解析错误。。。。。。】");
            throw new MyRunTimeExcption("【XML解析错误。。。。。。】");
        }

        String errCode = resultMap.get("err_code");
        String orderId = resultMap.get("out_trade_no");
        String returnCode = resultMap.get("return_code");
        String resultCode = resultMap.get("result_code");
        String acqSeqId = resultMap.get("transaction_id");

        // 检测反馈状况
        if (WECHAT_PAY_NOTTIFY_STATUS_FAIL.equals(returnCode)) {
            logger.warn("【用户支付后反馈请求失败。。。。。。】");
            String errorMessage = WeChatNotification.getMessage(errCode);
            logger.warn(errorMessage);
            throw new MyRunTimeExcption(errorMessage);
        }
        if (WECHAT_PAY_NOTTIFY_STATUS_FAIL.equals(resultCode)) {
            logger.warn("【支付订单业务失败。。。。。。】");
            String errorMessage = resultMap.get("err_code_des");
            logger.warn("【"+errorMessage+"】。。。。。。");
            throw new MyRunTimeExcption(errorMessage);
        }
        if (WECHAT_PAY_NOTTIFY_STATUS_SUCCESS.equals(returnCode) && WECHAT_PAY_NOTTIFY_STATUS_SUCCESS.equals(resultCode)) {

            // 支付成功后处理逻辑
            logger.warn("【订单请求成功。。。。。。】");
            super.payin(Long.parseLong(orderId), acqSeqId, Payment.PAY_MODE_WECHAT_BY_WAP);
            List<WeChatPaymentFeedback> list = weChatPaymentFeedbackService
                    .findWeChatPaymentFeedbackByOutTradeNo(orderId);

            if (null == list || list.isEmpty()) {
                WeChatPaymentFeedback weChatPaymentFeedback;

                try {
                    weChatPaymentFeedback = WeChatNotification.InjectedObj(new WeChatPaymentFeedback(), resultMap, true);
                    weChatPaymentFeedback.setCreateTime(new Date());

                } catch (IllegalAccessException e) {
                    logger.warn(e.getMessage());
                    throw new MyRunTimeExcption(e);
                } catch (InstantiationException e) {
                    logger.warn(e.getMessage());
                    throw new MyRunTimeExcption(e);
                }

                weChatPaymentFeedbackService.createWeChatPaymentFeedback(weChatPaymentFeedback);
            }
        } else {
            logger.warn("支付反馈失败。。。。。。");
            throw new MyRunTimeExcption("支付反馈失败。。。。。。");
        }

        Map<String, String> returnMap = new HashMap<String, String>();
        returnMap.put("return_code", WECHAT_PAY_NOTTIFY_STATUS_SUCCESS);
        returnMap.put("return_msg", WECHAT_PAY_NOTTIFY_RETURN_MSG_OK);
        String ResultXml = XmlAnalysisTools.resultData(returnMap);

        returnMap.put("xml", ResultXml);
        return returnMap;
    }

    @Override
    public PayParameter refund(Order order, Integer price) {
        return null;
    }
}
